package pl.com.like.sequoia.biojava.pdb.transform;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.zip.GZIPOutputStream;

import org.biojava.bio.structure.Structure;
import org.biojava.bio.structure.StructureException;
import org.biojava.bio.structure.align.ClusterAltAligs;
import org.biojava.bio.structure.align.StructurePairAligner;
import org.biojava.bio.structure.align.pairwise.AlternativeAlignment;
import org.biojava.bio.structure.io.PDBFileReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;

import pl.com.like.sequoia.biojava.util.IConnectionHelper;
import pl.com.like.sequoia.model.bio.BioObjectHandler;
import pl.com.like.sequoia.model.bio.enums.FileTypeEnum;
import pl.com.like.sequoia.model.bio.enums.SourceType;

public class PdbCompare implements IPdbCompare {

	private final Logger log = LoggerFactory.getLogger(PdbCompare.class);
	@Autowired
	private IConnectionHelper connectionHelper;

	/**
	 * {@inheritDoc}
	 * 
	 * @deprecated
	 * 
	 * @return
	 */
	@Deprecated
	public BioObjectHandler compare(BioObjectHandler objA, BioObjectHandler objB) {
		// TODO check & finish
		Assert.notNull(objA);
		Assert.notNull(objB);
		String extension = ".pdb";
		String objectId = "alig_" + objA.getName() + "_" + objB.getName();
		String outputfilename = objectId + extension;
		BioObjectHandler retVal = null;
		File tempOutFile = null;
		try {
			tempOutFile = File.createTempFile(outputfilename, extension);
			StructurePairAligner sc = new StructurePairAligner();

			// step1 : read molecules
			if (log.isDebugEnabled()) {
				log.debug("aligning " + objA.getName() + " vs. " + objB.getName());
			}
			PDBFileReader pfr = new PDBFileReader();
			Structure structureA = pfr.getStructure(objA.getPath());
			Structure structureB = pfr.getStructure(objB.getPath());

			// of course you do not have to use the full structures
			// you could also just use any set of atoms of your choice

			// step 2 : do the calculations
			sc.align(structureA, structureB);

			// if you want more control over the alignment parameters
			// use the StrucAligParameters
			// StrucAligParameters params = new StrucAligParameters();
			// params.setFragmentLength(8);
			// sc.align(s1,s2,params);

			AlternativeAlignment[] aligs = sc.getAlignments();

			// cluster similar results together
			ClusterAltAligs.cluster(aligs);

			// print the result:
			// the AlternativeAlignment object gives access to rotation matrices
			// / shift vectors.
			for (int i = 0; i < aligs.length; i++) {
				AlternativeAlignment aa = aligs[i];
				if (log.isDebugEnabled()) {
					log.debug(aa.toString());
				}
			}

			// convert AlternativeAlignment 1 to PDB file, so it can be opened
			// with a viewer of your choice
			// (e.g. Jmol, Rasmol)

			if (aligs.length > 0) {
				AlternativeAlignment aa1 = aligs[0];
				String pdbstr = aa1.toPDB(structureA, structureB);
				if (log.isInfoEnabled()) {
					log.info("writing alignment to {}", tempOutFile.getAbsolutePath());
				}
				FileOutputStream out = new FileOutputStream(tempOutFile);
				GZIPOutputStream gout = new GZIPOutputStream(out);
				PrintStream p = new PrintStream(gout);

				p.println(pdbstr);
				p.close();
				out.close();
				gout.close();
				retVal = connectionHelper.registerFile(objectId, FileTypeEnum.PDB_ZIP, tempOutFile, SourceType.USER);
			}
		} catch (FileNotFoundException e) {
			String msg = "Could not find a file object on filesystem";
			log.error(msg, e);
		} catch (IOException e) {
			String msg = "Could not read/write a file object on filesystem";
			log.error(msg, e);
		} catch (StructureException e) {
			String msg = "Could not compute alignment for this objects";
			StringBuilder sb = new StringBuilder(msg);
			sb.append(" ");
			sb.append(objA.toString());
			sb.append(" ");
			sb.append(objB.toString());
			msg = sb.toString();
			log.error(msg, e);
		}
		return retVal;

	}
}
